/// 求割点的模板题
#include <bits/stdc++.h>
using namespace std;
#include <bits/extc++.h>
using namespace __gnu_pbds;


namespace IO{

char *__abc147, *__xyz258, __ma369[1000000];
#define __hv007() ((__abc147==__xyz258) && (__xyz258=(__abc147=__ma369)+fread(__ma369,1,100000,stdin),__abc147==__xyz258) ? EOF : *__abc147++)

int getInt(){
	int sgn = 1;
	char ch = __hv007();
	while( ch != '-' && ( ch < '0' || ch > '9' ) ) ch = __hv007();
	if ( '-' == ch ) {sgn = 0;ch=__hv007();}
 
	int ret = (int)(ch-'0');
	while( '0' <= (ch=__hv007()) && ch <= '9' ) ret = ret * 10 + (int)(ch-'0');
	return sgn ? ret : -ret;
}

using llt = long long;

llt getLL(){
	int sgn = 1;
	char ch = __hv007();
	while( ch != '-' && ( ch < '0' || ch > '9' ) ) ch = __hv007();
	if ( '-' == ch ) {sgn = 0;ch=__hv007();}
 
	llt ret = (int)(ch-'0');
	while( '0' <= (ch=__hv007()) && ch <= '9' ) ret = ret * 10LL + (llt)(ch-'0');
	return sgn ? ret : -ret;    
}

char getChar(function<bool(char)> ok){
    char ch = __hv007();
    while(!ok(ch)) ch = __hv007();
    return ch;
}

}

struct CutBridgeTarjan{

using weight_t = int;
using vi = vector<int>;

struct edge_t{
    int from;
	int to;
	weight_t w;
	edge_t(int a, int b, int c):from(a),to(b),w(c){}
};

int N;
vector<edge_t> Edges; // 0-index
vector<vi> G; // 1-index

/// 点数和边数
void init(int n, int m=0){
    G.assign((N = n) + 1, {});
	Edges.clear();
	Edges.reserve(m + m);
}

void mkBiEdge(int a, int b, weight_t w=0){
	G[a].emplace_back(Edges.size());
	Edges.emplace_back(a, b, w);
	G[b].emplace_back(Edges.size());
	Edges.emplace_back(b, a, w);
}

void Trajan(){
    Dfn.assign(N + 1, TimeStamp = StackTop = 0);
    Low.assign(N + 1, 0);	
	IsCut.assign(N + 1, 0);
	AddBlocks.assign(N + 1, 0);

    IsVisited.assign(Edges.size(), 0);
    Stack.assign(Edges.size(), 0);
	IsBridge.assign(Edges.size(), BridgeCnt = 0);

	for(int i=1;i<=N;++i)if(0==Dfn[i])dfs(i, i);
	return;
}

void dfs(int u, int p){
	int v, son = 0;
	Dfn[u] = Low[u] = ++TimeStamp;

	for(auto i : G[u])if(not IsVisited[i]){
        IsVisited[i] = IsVisited[i ^ 1] = 1;

		if(0 == Dfn[v = Edges[i].to]){
			++son;
			dfs(v, u);
			if(Low[v] < Low[u]) Low[u] = Low[v];

			/// 桥
			if(Dfn[u] < Low[v]){
                IsBridge[i] = IsBridge[i ^ 1] = 1;
				++BridgeCnt;
			}

			/// 割点条件2
			if(u != p and Dfn[u] <= Low[v]){
				IsCut[u] = 1;
				++AddBlocks[u];
			}
		}else if(Dfn[v] < Low[u]){
			Low[u] = Dfn[v];
		}
	}

	/// 割点条件1
	if(u == p and son > 1) IsCut[u] = 1;
	if(u == p) AddBlocks[u] = son - 1;
	return;
}

vi Stack;
int StackTop;
int TimeStamp;
vi Dfn, Low;

vi IsVisited;
vi IsBridge;
int BridgeCnt;

vi AddBlocks;
vi IsCut;

};

CutBridgeTarjan T;
int N, M;

int main(){
#ifndef ONLINE_JUDGE
    freopen("1.txt", "r", stdin);
#endif
    // ios::sync_with_stdio(0); 
    // cin.tie(0); cout.tie(0);	
    using namespace IO;
	N = getInt(); M = getInt();
    T.init(N, M);
	for(int a,b,i=0;i<M;++i){
        a = getInt(); b = getInt();
		T.mkBiEdge(a, b, 0);
	}
	T.Trajan();
	int ans = accumulate(T.IsCut.begin(), T.IsCut.end(), 0);
	printf("%d\n", ans);
	for(int i=1;i<=N;++i)if(T.IsCut[i])printf("%d ", i);printf("\n");
	return 0;
}